package com.alibaba.otter.manager.web.service;

import com.alibaba.otter.manager.biz.common.exceptions.ManagerException;
import com.alibaba.otter.manager.biz.config.datacolumnpair.DataColumnPairGroupService;
import com.alibaba.otter.manager.biz.config.datacolumnpair.DataColumnPairService;
import com.alibaba.otter.manager.biz.config.datamedia.DataMediaService;
import com.alibaba.otter.manager.biz.config.datamediapair.DataMediaPairService;
import com.alibaba.otter.manager.biz.config.datamediasource.DataMediaSourceService;
import com.alibaba.otter.manager.biz.statistics.table.TableStatService;
import com.alibaba.otter.manager.web.dto.ColumnGroupDTO;
import com.alibaba.otter.manager.web.dto.ColumnPairDTO;
import com.alibaba.otter.manager.web.dto.CreateColumnGroupDTO;
import com.alibaba.otter.manager.web.dto.DataMediaPairDTO;
import com.alibaba.otter.manager.web.mapstruct.DataMediaPairMapper;
import com.alibaba.otter.shared.common.model.config.data.*;
import com.alibaba.otter.shared.common.model.statistics.table.TableStat;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

@Slf4j
@Service
public class DataMediaPairAggService {


    private final TableStatService tableStatService;

    private final DataMediaPairService dataMediaPairService;

    private final DataMediaPairMapper dataMediaPairMapper;

    private final DataMediaSourceService dataMediaSourceService;

    private final DataMediaService dataMediaService;

    private final DataColumnPairGroupService dataColumnPairGroupService;

    private final DataColumnPairService dataColumnPairService;

    public DataMediaPairAggService(TableStatService tableStatService,
                                   DataMediaPairService dataMediaPairService,
                                   DataMediaPairMapper dataMediaPairMapper,
                                   DataMediaSourceService dataMediaSourceService,
                                   DataMediaService dataMediaService,
                                   DataColumnPairGroupService dataColumnPairGroupService,
                                   DataColumnPairService dataColumnPairService) {
        this.tableStatService = tableStatService;
        this.dataMediaPairService = dataMediaPairService;
        this.dataMediaPairMapper = dataMediaPairMapper;
        this.dataMediaSourceService = dataMediaSourceService;
        this.dataMediaService = dataMediaService;
        this.dataColumnPairGroupService = dataColumnPairGroupService;
        this.dataColumnPairService = dataColumnPairService;
    }

    public List<DataMediaPairDTO> list(Long pipelineId) throws Exception {

        List<DataMediaPair> dataMediaPairs = dataMediaPairService.listByPipelineId(pipelineId);
        List<DataMediaPairDTO> dataMediaPairDTOS = dataMediaPairMapper.toDTO(dataMediaPairs);
        List<TableStat> tableStats = tableStatService.listTableStat(pipelineId);

        for (DataMediaPairDTO dataMediaPair : dataMediaPairDTOS) {
            int flag = 0;
            for (TableStat tableStat : tableStats) {
                if (dataMediaPair.getId().equals(tableStat.getDataMediaPairId())) {
                    dataMediaPair.setTableStat(tableStat);
                    flag = 1;
                    break;
                }
            }
            if (flag == 0) {
                TableStat tableStat = new TableStat();
                tableStat.setFileSize(0L);
                tableStat.setFileCount(0L);
                tableStat.setDeleteCount(0L);
                tableStat.setUpdateCount(0L);
                tableStat.setInsertCount(0L);
                // tableStat.setGmtModified(dataMediaPair.getGmtModified());
                dataMediaPair.setTableStat(tableStat);
            }
        }
        // 通过PipelineId不能获取到Channel状态，所以需要传递Channel对象
        return dataMediaPairDTOS;
    }

    public void batchCreate(List<String> batchPairContent, Long pipelineId) {
        try {
            for (String stringPair : batchPairContent) {
                List<String> pairData = Arrays.asList(stringPair.split(","));
                if (pairData.size() < 4) {
                    throw new ManagerException("[" + stringPair + "] the line not all parameters");
                }
                // build the pair source
                DataMedia<DataMediaSource> sourceDataMedia = new DataMedia<>();
                DataMediaSource sourceDataMediaSource = dataMediaSourceService.findById(Long.parseLong(StringUtils.trimToNull(pairData.get(2))));
                sourceDataMedia.setNamespace(StringUtils.trimToNull(pairData.get(0)));
                sourceDataMedia.setName(StringUtils.trimToNull(pairData.get(1)));
                sourceDataMedia.setSource(sourceDataMediaSource);
                Long sourceMediaId = dataMediaService.createReturnId(sourceDataMedia);
                sourceDataMedia.setId(sourceMediaId);
                // build the pair target
                DataMedia<DataMediaSource> targetDataMedia = new DataMedia<>();
                long weight = 5L;
                if (StringUtils.isNumeric(pairData.get(3)) && pairData.size() <= 5) {// 如果是纯数字，那说明是简化配置模式
                    DataMediaSource targetDataMediaSource = dataMediaSourceService.findById(Long.parseLong(StringUtils.trimToNull(pairData.get(3))));
                    targetDataMedia.setNamespace(StringUtils.trimToNull(pairData.get(0)));
                    targetDataMedia.setName(StringUtils.trimToNull(pairData.get(1)));
                    targetDataMedia.setSource(targetDataMediaSource);
                    Long targetMediaId = dataMediaService.createReturnId(targetDataMedia);
                    targetDataMedia.setId(targetMediaId);

                    if (pairData.size() == 5) {
                        weight = Long.parseLong(StringUtils.trimToNull(pairData.get(4)));
                    }
                } else {
                    DataMediaSource targetDataMediaSource = dataMediaSourceService.findById(Long.parseLong(StringUtils.trimToNull(pairData.get(5))));
                    targetDataMedia.setNamespace(StringUtils.trimToNull(pairData.get(3)));
                    targetDataMedia.setName(StringUtils.trimToNull(pairData.get(4)));
                    targetDataMedia.setSource(targetDataMediaSource);
                    Long targetMediaId = dataMediaService.createReturnId(targetDataMedia);
                    targetDataMedia.setId(targetMediaId);

                    if (pairData.size() >= 7) {
                        weight = Long.parseLong(StringUtils.trimToNull(pairData.get(6)));
                    }
                }

                // build the pair
                DataMediaPair dataMediaPair = new DataMediaPair();
                dataMediaPair.setSource(sourceDataMedia);
                dataMediaPair.setTarget(targetDataMedia);
                dataMediaPair.setPushWeight(weight);
                dataMediaPair.setPipelineId(pipelineId);

                dataMediaPairService.createIfNotExist(dataMediaPair);
            }
        } catch (Exception e) {
            log.error("create data media pair error", e);
        }
    }


    public ColumnPairDTO queryColumnPair(Long dataMediaPairId, Long sourceMediaId, Long targetMediaId) {

        DataMedia sourcedataMedia = dataMediaService.findById(sourceMediaId);
        DataMedia targetdataMedia = dataMediaService.findById(targetMediaId);

        List<String> sourceColumns = dataMediaService.queryColumnByMedia(sourcedataMedia);
        List<String> targetColumns = dataMediaService.queryColumnByMedia(targetdataMedia);

        List<String> underSourceColumns = new ArrayList<>();
        List<String> underTargetColumns = new ArrayList<>();

        List<ColumnPair> columnPairs = dataColumnPairService.listByDataMediaPairId(dataMediaPairId);

        if (CollectionUtils.isNotEmpty(columnPairs)) {
            for (ColumnPair columnPair : columnPairs) {
                if (columnPair.getSourceColumn() != null) {
                    underSourceColumns.add(columnPair.getSourceColumn().getName());
                }
                if (columnPair.getTargetColumn() != null) {
                    underTargetColumns.add(columnPair.getTargetColumn().getName());
                }
            }
        }
        ColumnPairDTO pair = new ColumnPairDTO();
        pair.setSourceMediaId(sourceMediaId);
        pair.setTargetMediaId(targetMediaId);
        pair.setSourceColumns(sourceColumns);
        pair.setTargetColumns(targetColumns);
        pair.setUnderSourceColumns(underSourceColumns);
        pair.setUnderTargetColumns(underTargetColumns);
        pair.setDataMediaPairId(dataMediaPairId);
        return pair;
    }

    public ColumnGroupDTO queryColumnGroup(Long dataMediaPairId, Long sourceMediaId, Long targetMediaId) {

        List<ColumnPair> columnPairs = dataColumnPairService.listByDataMediaPairId(dataMediaPairId);
        if (CollectionUtils.isEmpty(columnPairs)) {
            columnPairs.addAll(buildColumnPairFromDataMedia(dataMediaPairId, sourceMediaId, targetMediaId));
        } else {
            DataMediaPair dataMediaPair = dataMediaPairService.findById(dataMediaPairId);
            if (dataMediaPair.getColumnPairMode().isExclude()) {
                List<ColumnPair> allColumnPairs = buildColumnPairFromDataMedia(dataMediaPairId, sourceMediaId, targetMediaId);
                allColumnPairs.removeAll(columnPairs); // 如果是exclude模式，排除掉
                columnPairs = allColumnPairs;
            }
        }

        List<ColumnGroup> columnGroups = dataColumnPairGroupService.listByDataMediaPairId(dataMediaPairId);
        List<ColumnPair> columnPairGroup = new ArrayList<>();

        if (CollectionUtils.isNotEmpty(columnGroups)) {
            for (ColumnGroup columnGroup : columnGroups) {
                columnPairGroup = columnGroup.getColumnPairs();
            }
        }
        ColumnGroupDTO columnGroupDTO = new ColumnGroupDTO();
        // 未加入group的columnPair定义
        columnGroupDTO.setPreColumnPairs(columnPairs);
        // 当前group的columnPair定义
        columnGroupDTO.setColumnPairs(columnPairGroup);
        columnGroupDTO.setDataMediaPairId(dataMediaPairId);

        return columnGroupDTO;

    }

    private List<ColumnPair> buildColumnPairFromDataMedia(Long dataMediaPairId, Long sourceMediaId, Long targetMediaId) {
        List<ColumnPair> columnPairs = new ArrayList<>();
        List<String> sourceColumns = dataMediaService.queryColumnByMediaId(sourceMediaId);
        List<String> targetColumns = dataMediaService.queryColumnByMediaId(targetMediaId);

        if (CollectionUtils.isNotEmpty(sourceColumns) && CollectionUtils.isNotEmpty(targetColumns)) {
            for (String sourceColumn : sourceColumns) {
                for (String targetColumn : targetColumns) {
                    if (sourceColumn.equalsIgnoreCase(targetColumn)) {
                        ColumnPair columnPair = new ColumnPair(sourceColumn, targetColumn);
                        columnPair.setDataMediaPairId(dataMediaPairId);
                        columnPairs.add(columnPair);
                    }
                }
            }
        }

        return columnPairs;
    }


    public void createColumnPair(ColumnPairDTO pairDTO) {

        Long dataMediaPairId = pairDTO.getDataMediaPairId();
        DataMedia targetMedia = dataMediaPairService.findById(dataMediaPairId).getTarget();
        List<String> sourceColumnNames = pairDTO.getSourceColumns();
        List<String> targetColumnNames = pairDTO.getTargetColumns();
        if (!targetMedia.getSource().getType().isNapoli() && sourceColumnNames.size() != targetColumnNames.size()) {
            throw new ManagerException("映射对不对应");
        }
        List<ColumnPair> columnPairsInDb = dataColumnPairService.listByDataMediaPairId(dataMediaPairId);
        List<ColumnPair> columnPairsTemp = new ArrayList<>();
        List<String> columnPairsNameSource = new ArrayList<>();
        List<String> columnPairsNameTarget = new ArrayList<>();
        List<ColumnPair> columnPairs = new ArrayList<>();

        if (targetMedia.getSource().getType().isNapoli()) {
            for (ColumnPair columnPair : columnPairsInDb) {
                for (String sourceColumnName : sourceColumnNames) {
                    if (Objects.equals(columnPair.getSourceColumn().getName(), sourceColumnName)) {
                        columnPairsTemp.add(columnPair);
                        columnPairsNameSource.add(sourceColumnName);
                    }
                }
            }
            // 要从数据库中删除这些columnPair
            columnPairsInDb.removeAll(columnPairsTemp);
            sourceColumnNames.removeAll(columnPairsNameSource);

            for (String columnName : sourceColumnNames) {
                ColumnPair columnPair = new ColumnPair();
                columnPair.setSourceColumn(new Column(columnName));
                columnPair.setDataMediaPairId(dataMediaPairId);
                columnPairs.add(columnPair);
            }
        } else if (targetMedia.getSource().getType().isMysql() || targetMedia.getSource().getType().isOracle()) {
            for (ColumnPair columnPair : columnPairsInDb) {
                int i = 0;
                for (String sourceColumnName : sourceColumnNames) {
                    if (Objects.equals(columnPair.getSourceColumn().getName(), sourceColumnName)
                            && Objects.equals(columnPair.getTargetColumn().getName(), targetColumnNames.get(i))) {
                        columnPairsTemp.add(columnPair);
                        columnPairsNameSource.add(sourceColumnName);
                        columnPairsNameTarget.add(targetColumnNames.get(i));
                    }
                    i++;
                }
            }
            // 要从数据库中删除这些columnPair
            columnPairsInDb.removeAll(columnPairsTemp);
            sourceColumnNames.removeAll(columnPairsNameSource);
            targetColumnNames.removeAll(columnPairsNameTarget);

            int i = 0;
            for (String columnName : sourceColumnNames) {
                ColumnPair columnPair = new ColumnPair();
                columnPair.setSourceColumn(new Column(columnName));
                columnPair.setTargetColumn(new Column(targetColumnNames.get(i)));
                columnPair.setDataMediaPairId(dataMediaPairId);
                columnPairs.add(columnPair);
                i++;
            }
        }

        for (ColumnPair columnPair : columnPairsInDb) {
            dataColumnPairService.remove(columnPair.getId());
        }

        if (CollectionUtils.isEmpty(columnPairs)) {
            return;
        }
        dataColumnPairService.createBatch(columnPairs);
    }


    public void createColumnGroup(CreateColumnGroupDTO q) {
        List<String> columnPairStrings = q.getColumnPairs();
        ColumnGroup columnGroup = new ColumnGroup();
        List<ColumnPair> columnPairs = new ArrayList<>();
        for (String columnPairString : columnPairStrings) {
            ColumnPair columnPair = new ColumnPair();
            String[] temp = columnPairString.split(":");
            columnPair.setSourceColumn(new Column(temp[0]));
            columnPair.setTargetColumn(new Column(temp[1]));
            columnPair.setDataMediaPairId(q.getDataMediaPairId());
            columnPairs.add(columnPair);
        }

        columnGroup.setColumnPairs(columnPairs);
        columnGroup.setDataMediaPairId(q.getDataMediaPairId());

        dataColumnPairGroupService.removeByDataMediaPairId(q.getDataMediaPairId());
        dataColumnPairGroupService.create(columnGroup);

    }


}
